use std::cmp::min;
use bevy::app::AppExit;
use bevy::prelude::*;
use rand::Rng;
use std::collections::HashSet;

// 引入各个模块
mod tank;
mod team;
mod state;
mod message;
mod spatial_grid;

use tank::{Tank, Location, Velocity, Position};
use team::Team;
use state::SimulationState;
use message::DigitalTwinMessage;
use spatial_grid::SpatialGrid;

const WORLD_WIDTH: f32 = 10000.0;
const WORLD_HEIGHT: f32 = 10000.0;
const TANK_SPEED: f32 = 1.0;
const TANK_SIZE: f32 = 2.0;
const INITIAL_TANK_COUNT: usize = 100_000;
const INITIAL_TEAM_COUNT: usize = 10;

fn main() {
    println!("Starting tank simulation...");
    env_logger::builder()
        .filter_level(log::LevelFilter::Info)
        .init();

    App::new()
        .add_plugins(DefaultPlugins.set(bevy::log::LogPlugin {
            level: bevy::log::Level::INFO,
            filter: "info".to_string(),
            ..default()
        }))
        //.add_plugins(MinimalPlugins)
        // .insert_resource(SimulationState {
        //     step: 0,
        //     alive_count: INITIAL_TEAM_COUNT,
        // })
        .insert_resource(SpatialGrid {
            grid: std::collections::HashMap::new(),
        })
        // 添加事件系统
        .add_event::<DigitalTwinMessage>()
        //.add_systems(Startup, setup)
        .add_systems(
            Startup,
            |mut commands: Commands, mut team_query: Query<&mut Team>| {
                setup(commands, team_query);
            },
        )
        .add_systems(Startup, startupmq)
        .add_systems(Update, handle_external_messages)
        .add_systems(
            Update,
            (move_tanks, update_spatial_grid, detect_collisions).chain(),
        )
        .add_systems(Update, print_status.run_if(should_print_status))
        .add_systems(Update, check_simulation_end.run_if(should_end_simulation))
        // 添加处理数字孪生消息的系统
        .add_systems(Update, handle_digital_twin_messages)
        .run();
}

/// 初始化游戏场景，创建指定数量的坦克实体
///
/// 该函数负责在游戏世界中随机生成初始坦克，每个坦克都具有唯一ID、
/// 随机位置和随机速度。使用Bevy的命令系统来创建实体并添加组件。
///
/// # 参数
/// * `commands` - Bevy ECS系统的命令缓冲区，用于创建实体和添加组件
fn setup(mut commands: Commands, mut team_query: Query<&mut Team>) {
    let mut rng = rand::thread_rng();
    let min_tanks = INITIAL_TANK_COUNT / 2 / INITIAL_TEAM_COUNT;
    let max_tanks = INITIAL_TANK_COUNT * 2 / INITIAL_TEAM_COUNT;
    let mut tank_count: usize =0;
    info!("Creating {} tanks...", INITIAL_TANK_COUNT);
    for i in 0..INITIAL_TEAM_COUNT {
        // 创建一个新的队伍实体并添加到命令队列中
        // 队伍ID基于索引和初始坦克数量计算得出，确保唯一性
        // 初始存活数量设置为0
        let team_id =(i + 1) * INITIAL_TANK_COUNT + 1;
        let team_tank_count: usize = rng.random_range(min_tanks..max_tanks);
        let team = Team {
            id: team_id ,
            alive_count: team_tank_count,
        };
        info!("Creating team-- {}", team_id);
        commands.spawn(team);

        for j in 1..team_tank_count {
            let x = rng.random_range(0.0..WORLD_WIDTH);
            let y = rng.random_range(0.0..WORLD_HEIGHT);
            let vx = rng.random_range(-TANK_SPEED..=TANK_SPEED);
            let vy = rng.random_range(-TANK_SPEED..=TANK_SPEED);


            // 创建一个新的坦克实体并添加到游戏世界中
            // 该函数会初始化坦克的所有基本属性，包括位置、速度、团队信息等
            let tank = Tank {
                id: team_id + j,                    // 坦克的唯一标识符
                alive: true,             // 坦克初始状态为存活
                location: Location { x, y },     // 坦克的初始位置坐标
                velocity: Velocity { x: vx, y: vy }, // 坦克的初始速度向量
                messages: Vec::new(),    // 坦克的消息队列，初始为空
                team_id,                 // 坦克所属的团队ID
            };
            if (j <5 || j > team_tank_count - 3){
                info!("Creating tank {}", tank.id);
            }
            commands.spawn(tank);
         //   team_query.join(team);
            // 更新对应团队的存活数量
            tank_count += 1;
        }
        info!("Team {},Created {} tanks",team_id, team_tank_count);

    }
    // 添加初始状态打印
    info!("Initial setup completed. Total tanks: {}", tank_count);

    // 修改 SimulationState 的存活数量
    commands.insert_resource(SimulationState {
        step: 0,
        alive_count: tank_count,
    })
}

/// 移动所有存活的坦克实体
///
/// 该函数遍历所有带有 Alive 组件的实体，更新它们的位置信息，
/// 并处理边界碰撞检测和反弹逻辑。
///
/// # 参数
/// * `query` - 查询所有带有 Alive 组件的实体及其位置和速度信息
fn move_tanks(mut query: Query<&mut Tank>) {
    let tank_count = query.iter().count();
    println!("Moving {} tanks", tank_count);

    // 使用并行迭代提高性能
    // 性能分析：对于100,000个坦克实体，此处可能成为性能瓶颈
    // 建议：使用trace或info级别日志监控执行时间
    query.par_iter_mut().for_each(|mut tank| {
        tank.move_tank();
    });

    trace!("Finished moving tanks");
}

/// 更新空间网格系统
///
/// 该函数负责维护一个空间网格数据结构，用于高效地进行碰撞检测和邻近查询。
/// 它会清空现有的网格，然后根据所有存活实体的当前位置重新构建网格。
///
/// # 参数
/// * `spatial_grid`: 可变资源引用，指向存储空间网格数据的结构
/// * `query`: 查询所有带有Alive组件的实体及其位置信息
fn update_spatial_grid(mut spatial_grid: ResMut<SpatialGrid>, query: Query<(Entity, &Tank)>) {
    // 清空网格
    trace!("Updating spatial grid...");
    spatial_grid.grid.clear();

    // 将所有存活的坦克放入网格中
    // 使用并行迭代提高性能
    // 性能分析：对于100,000个坦克实体，此处可能成为性能瓶颈
    // 原因：需要为每个实体计算网格位置并存储到grid_updates向量中
    let mut grid_updates: Vec<(Position, Entity)> = Vec::new();

    for (entity, tank) in query.iter() {
        if !tank.alive {
            continue;
        }

        let grid_pos = Position {
            x: (tank.location.x / TANK_SIZE) as i32,
            y: (tank.location.y / TANK_SIZE) as i32,
        };
        grid_updates.push((grid_pos, entity));
    }

    // 更新网格
    // 性能分析：此处对grid_updates进行遍历，可能成为性能瓶颈
    // 建议：考虑使用HashMap的entry API优化或并行处理
    for (grid_pos, entity) in grid_updates {
        spatial_grid
            .grid
            .entry(grid_pos)
            .or_insert_with(Vec::new)
            .push(entity);
    }
}

/// 碰撞检测函数，用于检测并处理坦克之间的碰撞
///
/// 该函数通过空间网格来检测同一网格位置上的多个坦克实体，
/// 并将这些发生碰撞的坦克标记为销毁状态，同时更新模拟状态。
///
/// # 参数
/// * `commands` - ECS命令队列，用于执行实体操作
/// * `spatial_grid` - 空间网格资源，用于快速定位实体位置
/// * `mut query` - 可变查询，用于访问坦克组件状态
/// * `state` - 模拟状态资源，用于跟踪存活实体数量和步数
fn detect_collisions(
    commands: Commands,
    spatial_grid: Res<SpatialGrid>,
    mut query: Query<&mut Tank>,
    mut team_query: Query<&mut Team>,
    mut state: ResMut<SimulationState>,
) {
 /*!
 * 处理空间网格中的坦克碰撞检测与销毁逻辑
 *
 * 该函数遍历空间网格中的每个格子，检测同一格子内不同队伍的坦克，
 * 并根据坦克的探测结果发送销毁消息，最后统一处理销毁和消息分发。
 *
 * # 参数说明
 * * `spatial_grid` - 空间网格，用于快速查找同一区域内的实体
 * * `query` - 用于查询和修改坦克实体的查询器
 * * `team_query` - 用于查询和修改队伍实体的查询器
 * * `state` - 全局游戏状态，包含存活数量等信息
 */
    // 在detect_collisions函数中添加一个HashMap来存储tank_id到实体的映射
    let mut tank_id_to_entity: std::collections::HashMap<usize, &Tank> = std::collections::HashMap::new();

    for x in query.iter() {
        tank_id_to_entity.insert(x.id, x);
    }
    let mut destroy_list = Vec::new();
    let mut message_map = std::collections::HashMap::new();

    // 遍历空间网格中的每个格子，检测需要销毁的坦克
    // 性能分析：遍历整个网格可能是性能瓶颈，尤其是当网格数量很大时
    for (_, entities) in &spatial_grid.grid {
        // 如果格子内实体数小于等于1，跳过检测
        if entities.len() <= 1 {
            continue;
        }

        let mut teams_in_cell = std::collections::HashMap::new();
        let mut tanks_in_cell = Vec::new();

        // 收集格子内所有存活的坦克信息
        // 性能分析：对entities进行遍历并执行query.get()可能成为性能瓶颈
        for &entity in entities {
            if let Ok(tank) = query.get(entity) {
                if tank.alive {
                    teams_in_cell.insert(entity, tank.team_id);
                    tanks_in_cell.push(tank);
                }
            }
        }

        // 如果格子内队伍数小于等于1，跳过检测
        if teams_in_cell.len() <= 1 {
            continue;
        }

        // 检测每个坦克的攻击目标并生成销毁消息
        // 性能分析：嵌套循环和detect_targets方法可能成为性能瓶颈
        for &entity in entities {
            if let Ok(tank) = query.get(entity) {
                if !tank.alive {
                    continue;
                }

                let targets = tank.detect_targets(&tanks_in_cell);
                for target_id in targets {
                    let message = tank.send_destroy_message(target_id);
                    message_map
                        .entry(target_id)
                        .or_insert_with(Vec::new)
                        .push(message);
                }

                destroy_list.push(entity);
            }
        }
    }

    // 应用销毁和消息
    // 性能分析：遍历destroy_list并执行query.get_mut()可能成为性能瓶颈
    state.step = state.step + 1;
    for entity in destroy_list {
        if let Ok(mut tank) = query.get_mut(entity) {
            tank.destroy_self();
            state.alive_count = state.alive_count.saturating_sub(1);

            for mut team in team_query.iter_mut() {
                if team.id == tank.team_id {
                    team.alive_count = team.alive_count.saturating_sub(1);
                }
            }
        }
    }

    // 分发消息
    // 性能分析：双重循环遍历message_map和query.iter_mut()可能成为严重性能瓶颈
    // 建议：考虑使用HashMap存储tank_id到tank实体的映射以提高查找效率
    for (target_id, messages) in message_map {
        for mut tank in query.iter_mut() {
            if tank.id == target_id {
                for message in messages {
                    tank.receive_destroy_message(message);
                }
                break;
            }
        }
    }

}

/// 打印模拟器当前状态信息
///
/// 该函数用于输出模拟器的当前步数和存活坦克数量等状态信息，
/// 便于调试和监控模拟器运行情况。
///
/// # 参数
///
/// * `state` - 包含模拟器状态信息的资源引用，包含当前步数和存活坦克数量
/// * `team_query` - 团队查询，用于获取团队信息
fn print_status(state: Res<SimulationState>, team_query: Query<&Team>) {
    info!("Step {}: {} tanks alive", state.step, state.alive_count);
    // 打印每个团队的存活数量
    for team in team_query.iter() {
        info!("Team {}: {} tanks alive", team.id, team.alive_count);
    }
}

/// 判断是否应该打印状态信息
///
/// 当模拟步数为100的倍数，或者存活个体数小于1000时，返回true
///
/// # 参数
/// * `state` - 包含模拟状态信息的资源引用，包含当前步数和存活个体数
///
/// # 返回值
/// * `bool` - 如果应该打印状态信息则返回true，否则返回false
fn should_print_status(state: Res<SimulationState>) -> bool {
    state.step % 100 == 0 || state.alive_count < 1000
}

/// 检查模拟是否应该结束的系统函数
///
/// 该函数在每一帧检查模拟状态，当满足结束条件时触发应用退出事件。
/// 结束条件包括：存活单位数量小于1000或模拟步数超过10000。
///
/// # 参数
/// * `state` - 模拟状态资源的只读访问，包含当前的存活单位数量和步数信息
/// * `exit` - 应用退出事件的可变写入器，用于发送退出信号
///
/// # 返回值
/// 无返回值，但可能通过exit参数发送AppExit事件
fn check_simulation_end(state: Res<SimulationState>, mut exit: EventWriter<AppExit>) {
    // 检查模拟结束条件：存活单位过少或步数超限
    if state.alive_count < 1000 || state.step > 10000 {
        println!("Simulation finished after {} steps", state.step);
        println!("Final alive tanks: {}", state.alive_count);

        exit.write(AppExit::Success);
    }
}

/// 判断是否应该结束模拟运行
///
/// 该函数根据当前模拟状态来决定是否需要终止模拟进程。
/// 当存活个体数量过少或模拟步数达到上限时，模拟将被终止。
///
/// # 参数
/// * `state` - 包含当前模拟状态信息的资源引用，包含存活个体数量和当前步数
///
/// # 返回值
/// * `bool` - 当需要结束模拟时返回true，否则返回false
///
/// # 结束条件
/// 模拟会在以下任一条件满足时结束：
/// - 存活个体数量少于1000个
/// - 模拟步数超过10000步
fn should_end_simulation(state: Res<SimulationState>) -> bool {
    state.alive_count < 1000 || state.step > 10000
}

/// 处理来自数字孪生系统的外部消息
///
/// 该系统接收DigitalTwinMessage事件，并将消息发送给具有匹配ID的坦克实体
fn handle_digital_twin_messages(
    mut digital_twin_events: EventReader<DigitalTwinMessage>,
    mut query: Query<&mut Tank>,
) {
    for event in digital_twin_events.read() {
        // 查找具有匹配ID的坦克
        for mut tank in query.iter_mut() {
            if tank.id == event.tank_id {
                println!("Tank {} received message: {}", tank.id, event.message);
                // 保存消息到tank内的数组
                tank.messages.push(event.message.clone());
                break;
            }
        }
    }
}

/// 启动消息队列系统，在单独的线程中定期向随机坦克发送消息
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
/// 启动消息队列系统，在单独的线程中定期向随机坦克发送消息use std::sync::{Arc, Mutex};

#[derive(Resource)]
struct MessageReceiver(Arc<Mutex<mpsc::Receiver<DigitalTwinMessage>>>);

fn startupmq(mut commands: Commands) {
    let (sender, receiver) = mpsc::channel::<DigitalTwinMessage>();
    let receiver = Arc::new(Mutex::new(receiver));
    commands.insert_resource(MessageReceiver(receiver));

    thread::spawn(move || {
        let mut rng = rand::thread_rng();

        loop {
            for _ in 0..10 {
                let tank_id = rng.gen_range(0..INITIAL_TANK_COUNT);
                let message = format!("Hello from thread at {:?}", std::time::Instant::now());
                let event = DigitalTwinMessage { tank_id, message };

                if sender.send(event).is_err() {
                    return; // receiver dropped
                }
            }

            thread::sleep(std::time::Duration::from_secs(1));
        }
    });
}

fn handle_external_messages(
    receiver: Res<MessageReceiver>,
    mut digital_twin_events: EventWriter<DigitalTwinMessage>,
) {
    if let Ok(receiver) = receiver.0.lock() {
        while let Ok(event) = receiver.try_recv() {
            digital_twin_events.write(event);
        }
    }
}